home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / nasm095s.zip / LABELS.C < prev    next >
C/C++ Source or Header  |  1997-07-27  |  8KB  |  297 lines

  1. /* labels.c  label handling for the Netwide Assembler
  2.  *
  3.  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  4.  * Julian Hall. All rights reserved. The software is
  5.  * redistributable under the licence given in the file "Licence"
  6.  * distributed in the NASM archive.
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include "nasm.h"
  13. #include "nasmlib.h"
  14.  
  15. /*
  16.  * A local label is one that begins with exactly one period. Things
  17.  * that begin with _two_ periods are NASM-specific things.
  18.  */
  19. #define islocal(l) ((l)[0] == '.' && (l)[1] != '.')
  20.  
  21. #define LABEL_BLOCK  320           /* no. of labels/block */
  22. #define LBLK_SIZE    (LABEL_BLOCK*sizeof(union label))
  23. #define LABEL_HASHES 32               /* no. of hash table entries */
  24.  
  25. #define END_LIST -3               /* don't clash with NO_SEG! */
  26. #define END_BLOCK -2
  27. #define BOGUS_VALUE -4
  28.  
  29. #define PERMTS_SIZE  4096           /* size of text blocks */
  30.  
  31. /* values for label.defn.is_global */
  32. #define NOT_DEFINED_YET 0
  33. #define LOCAL_SYMBOL 1
  34. #define GLOBAL_SYMBOL 2
  35. #define GLOBAL_PLACEHOLDER 3
  36.  
  37. union label {                   /* actual label structures */
  38.     struct {
  39.     long segment, offset;
  40.         char *label;
  41.     int is_global;
  42.     } defn;
  43.     struct {
  44.     long movingon, dummy;
  45.     union label *next;
  46.     } admin;
  47. };
  48.  
  49. struct permts {                   /* permanent text storage */
  50.     struct permts *next;           /* for the linked list */
  51.     int size, usage;               /* size and used space in ... */
  52.     char data[PERMTS_SIZE];           /* ... the data block itself */
  53. };
  54.  
  55. static union label *ltab[LABEL_HASHES];/* using a hash table */
  56. static union label *lfree[LABEL_HASHES];/* pointer into the above */
  57. static struct permts *perm_head;      /* start of perm. text storage */
  58. static struct permts *perm_tail;      /* end of perm. text storage */
  59.  
  60. static void init_block (union label *blk);
  61. static char *perm_copy (char *string1, char *string2);
  62.  
  63. static char *prevlabel;
  64.  
  65. /*
  66.  * Internal routine: finds the `union label' corresponding to the
  67.  * given label name. Creates a new one, if it isn't found, and if
  68.  * `create' is TRUE.
  69.  */
  70. static union label *find_label (char *label, int create) {
  71.     int hash = 0;
  72.     char *p, *prev;
  73.     int prevlen;
  74.     union label *lptr;
  75.  
  76.     if (islocal(label))
  77.     prev = prevlabel;
  78.     else
  79.     prev = "";
  80.     prevlen = strlen(prev);
  81.     p = prev;
  82.     while (*p) hash += *p++;
  83.     p = label;
  84.     while (*p) hash += *p++;
  85.     hash %= LABEL_HASHES;
  86.     lptr = ltab[hash];
  87.     while (lptr->admin.movingon != END_LIST) {
  88.     if (lptr->admin.movingon == END_BLOCK) {
  89.         lptr = lptr->admin.next;
  90.         if (!lptr)
  91.         break;
  92.     }
  93.     if (!strncmp(lptr->defn.label, prev, prevlen) &&
  94.         !strcmp(lptr->defn.label+prevlen, label))
  95.         return lptr;
  96.     lptr++;
  97.     }
  98.     if (create) {
  99.     if (lfree[hash]->admin.movingon == END_BLOCK) {
  100.         /*
  101.          * must allocate a new block
  102.          */
  103.         lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE);
  104.         lfree[hash] = lfree[hash]->admin.next;
  105.         init_block(lfree[hash]);
  106.     }
  107.  
  108.     lfree[hash]->admin.movingon = BOGUS_VALUE;
  109.     lfree[hash]->defn.label = perm_copy (prev, label);
  110.     lfree[hash]->defn.is_global = NOT_DEFINED_YET;
  111.     return lfree[hash]++;
  112.     } else
  113.     return NULL;
  114. }
  115.  
  116. int lookup_label (char *label, long *segment, long *offset) {
  117.     union label *lptr;
  118.  
  119.     lptr = find_label (label, 0);
  120.     if (lptr && (lptr->defn.is_global == LOCAL_SYMBOL ||
  121.          lptr->defn.is_global == GLOBAL_SYMBOL)) {
  122.     *segment = lptr->defn.segment;
  123.     *offset = lptr->defn.offset;
  124.     return 1;
  125.     } else
  126.     return 0;
  127. }
  128.  
  129. void define_label_stub (char *label, efunc error) {
  130.     union label *lptr;
  131.  
  132.     if (!islocal(label)) {
  133.     lptr = find_label (label, 1);
  134.     if (!lptr)
  135.         error (ERR_PANIC, "can't find label `%s' on pass two", label);
  136.     if (*label != '.')
  137.         prevlabel = lptr->defn.label;
  138.     }
  139. }
  140.  
  141. void define_label (char *label, long segment, long offset,
  142.            struct ofmt *ofmt, efunc error) {
  143.     union label *lptr;
  144.  
  145.     lptr = find_label (label, 1);
  146.     switch (lptr->defn.is_global) {
  147.       case NOT_DEFINED_YET:
  148.     lptr->defn.is_global = LOCAL_SYMBOL;
  149.     break;
  150.       case GLOBAL_PLACEHOLDER:
  151.     lptr->defn.is_global = GLOBAL_SYMBOL;
  152.     break;
  153.       default:
  154.     error(ERR_NONFATAL, "symbol `%s' redefined", label);
  155.     return;
  156.     }
  157.  
  158.     if (label[0] != '.')           /* not local, but not special either */
  159.     prevlabel = lptr->defn.label;
  160.     else if (label[1] != '.' && !*prevlabel)
  161.     error(ERR_NONFATAL, "attempt to define a local label before any"
  162.           " non-local labels");
  163.  
  164.     lptr->defn.segment = segment;
  165.     lptr->defn.offset = offset;
  166.  
  167.     ofmt->symdef (lptr->defn.label, segment, offset,
  168.           lptr->defn.is_global == GLOBAL_SYMBOL);
  169. }
  170.  
  171. void define_common (char *label, long segment, long size,
  172.             struct ofmt *ofmt, efunc error) {
  173.     union label *lptr;
  174.  
  175.     lptr = find_label (label, 1);
  176.     switch (lptr->defn.is_global) {
  177.       case NOT_DEFINED_YET:
  178.     lptr->defn.is_global = LOCAL_SYMBOL;
  179.     break;
  180.       case GLOBAL_PLACEHOLDER:
  181.     lptr->defn.is_global = GLOBAL_SYMBOL;
  182.     break;
  183.       default:
  184.     error(ERR_NONFATAL, "symbol `%s' redefined", label);
  185.     return;
  186.     }
  187.  
  188.     if (label[0] != '.')           /* not local, but not special either */
  189.     prevlabel = lptr->defn.label;
  190.     else
  191.     error(ERR_NONFATAL, "attempt to define a local label as a "
  192.           "common variable");
  193.  
  194.     lptr->defn.segment = segment;
  195.     lptr->defn.offset = 0;
  196.  
  197.     ofmt->symdef (lptr->defn.label, segment, size, 2);
  198. }
  199.  
  200. void declare_as_global (char *label, efunc error) {
  201.     union label *lptr;
  202.  
  203.     if (islocal(label)) {
  204.     error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
  205.           " global", label);
  206.     return;
  207.     }
  208.     lptr = find_label (label, 1);
  209.     switch (lptr->defn.is_global) {
  210.       case NOT_DEFINED_YET:
  211.     lptr->defn.is_global = GLOBAL_PLACEHOLDER;
  212.     break;
  213.       case GLOBAL_PLACEHOLDER:           /* already done: silently ignore */
  214.       case GLOBAL_SYMBOL:
  215.     break;
  216.       case LOCAL_SYMBOL:
  217.     error(ERR_NONFATAL, "symbol `%s': [GLOBAL] directive must"
  218.           " appear before symbol definition", label);
  219.     break;
  220.     }
  221. }
  222.  
  223. int init_labels (void) {
  224.     int i;
  225.  
  226.     for (i=0; i<LABEL_HASHES; i++) {
  227.     ltab[i] = (union label *) nasm_malloc (LBLK_SIZE);
  228.     if (!ltab[i])
  229.         return -1;               /* can't initialise, panic */
  230.     init_block (ltab[i]);
  231.     lfree[i] = ltab[i];
  232.     }
  233.  
  234.     perm_head = perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
  235.     if (!perm_head)
  236.         return -1;
  237.  
  238.     perm_head->next = NULL;
  239.     perm_head->size = PERMTS_SIZE;
  240.     perm_head->usage = 0;
  241.  
  242.     prevlabel = "";
  243.  
  244.     return 0;
  245. }
  246.  
  247. void cleanup_labels (void) {
  248.     int i;
  249.  
  250.     for (i=0; i<LABEL_HASHES; i++) {
  251.     union label *lptr, *lhold;
  252.  
  253.     lptr = lhold = ltab[i];
  254.  
  255.     while (lptr) {
  256.         while (lptr->admin.movingon != END_BLOCK) lptr++;
  257.         lptr = lptr->admin.next;
  258.         nasm_free (lhold);
  259.         lhold = lptr;
  260.     }
  261.     }
  262.  
  263.     while (perm_head) {
  264.     perm_tail = perm_head;
  265.     perm_head = perm_head->next;
  266.     nasm_free (perm_tail);
  267.     }
  268. }
  269.  
  270. static void init_block (union label *blk) {
  271.     int j;
  272.  
  273.     for (j=0; j<LABEL_BLOCK-1; j++)
  274.         blk[j].admin.movingon = END_LIST;
  275.     blk[LABEL_BLOCK-1].admin.movingon = END_BLOCK;
  276.     blk[LABEL_BLOCK-1].admin.next = NULL;
  277. }
  278.  
  279. static char *perm_copy (char *string1, char *string2) {
  280.     char *p, *q;
  281.     int len = strlen(string1)+strlen(string2)+1;
  282.  
  283.     if (perm_tail->size - perm_tail->usage < len) {
  284.     perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
  285.     perm_tail = perm_tail->next;
  286.     perm_tail->next = NULL;
  287.     perm_tail->size = PERMTS_SIZE;
  288.     perm_tail->usage = 0;
  289.     }
  290.     p = q = perm_tail->data + perm_tail->usage;
  291.     while ( (*q = *string1++) ) q++;
  292.     while ( (*q++ = *string2++) );
  293.     perm_tail->usage = q - perm_tail->data;
  294.  
  295.     return p;
  296. }
  297.